package com.adun.springsecuritydemo.config;

import com.adun.springsecuritydemo.handler.MyAccessDeniedHandler;
import com.adun.springsecuritydemo.handler.MyAuthenticationFailureHandler;
import com.adun.springsecuritydemo.handler.MyAuthenticationSuccessHandler;
import com.adun.springsecuritydemo.service.impl.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * Security Configuration
 *
 * @author zhudunfeng
 * @date 2021/6/24 17:46
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//    @Autowired
//    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //表单提交
        http.formLogin()
                //自定义入参，必须与form表单对应,默认与UsernamePasswordAuthenticationFilter对应
                .usernameParameter("username123")
                .passwordParameter("password123")
                //自定义登录页
//                .loginPage("/login.html")
                //开启csrf，使用
                .loginPage("/showLogin")
                //必须和表单提交的接口一样，会去执行自定义登录逻辑
//                .loginProcessingUrl("/login")
                //登录成功后跳转的页面，POST请求
                .successForwardUrl("/toMain")
                //自定义登录成功处理器
//                .successHandler(new MyAuthenticationSuccessHandler("/main.html"))
                //登录失败后跳转的页面，POST请求
                .failureForwardUrl("/toError");
                //自定义登录失败处理器
//                .failureHandler(new MyAuthenticationFailureHandler("/error.html"));

        //授权【登录之前的东西都需要授权】
        http.authorizeRequests()
                //放行/error.html不需要认证
                .antMatchers("/error.html").permitAll()
                //放行/login.html不需要认证
//                .antMatchers("/login.html").permitAll()
                //打开csrf后,使用模板内的login
                .antMatchers("/showLogin").permitAll()
                //放行静态资源
//                .antMatchers("/css/**","/js/**","/images/**").permitAll()
//                .antMatchers("/css/**","/js/**","/images/**").access("permitAll")
                //放行后缀为.png
//                .antMatchers("/**/*.png").permitAll()
                //放行后缀.png,正则表达式
//                .regexMatchers(".+[.]png").permitAll()
                //指定请求方式
//                .regexMatchers(HttpMethod.POST,"/demo").permitAll()
//                .regexMatchers("/demo").permitAll()
//                .antMatchers("/xxx/demo").permitAll()
//                .mvcMatchers("/demo").servletPath("/xxx").permitAll()

                //权限控制，严格区分大小写--->匹配不上，会报403
                //基于权限
//                .antMatchers("/main1.html").hasAuthority("admiN")
//                .antMatchers("/main1.html").hasAnyAuthority("admin","admiN")

                //基于角色[严格区分大小写]
//                .antMatchers("/main1.html").hasRole("abC")
//                .antMatchers("/main1.html").access("hasRole('abc')")
//                .antMatchers("/main1.html").hasAnyRole("abC","abc")

                //基于ip地址
//                .antMatchers("/main1.html").hasIpAddress("127.0.0.1")

                //所有请求必须认证（登录）才能访问
                .anyRequest().authenticated();
        //自定义access方法
//        .anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");

        //异常处理
        http.exceptionHandling()
                .accessDeniedHandler(new MyAccessDeniedHandler());


        //记住我
        http.rememberMe()
                //设置数据源
                .tokenRepository(persistentTokenRepository)
                //设置参数
//                .rememberMeParameter()
                //超时时间，默认两周
        .tokenValiditySeconds(60).
        userDetailsService(userDetailService);

        http.logout()
                //自定义登出地址，必须与页面请求地址保持一致
//                .logoutUrl("/user/logout")
                //退出成功后跳转的页面
                .logoutSuccessUrl("/login.html");

        //关闭csrf防护，关闭跨站请求伪造
//        http.csrf().disable();


    }

    //加密-匹配
    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        //设置数据源
        jdbcTokenRepository.setDataSource(dataSource);
        //自动建表，第一次启动时开启，第二次启动时注释掉
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

}
